/*
 * CITS2230 Operating Systems - Programming Project
 * Author:           Guilherme R. Lampert
 * Student number:   21203005
 */

#include "FcfsScheduler.hpp"

FcfsScheduler::FcfsScheduler(
		int memDumpTimeStep,
		const std::string & procListFile,
		const std::string & outputFile)
		: Scheduler(memDumpTimeStep, procListFile, outputFile)
{
	DLog("Scheduler is of type First Come First Served (FCFS)");
}

FcfsScheduler::~FcfsScheduler()
{
	DLog("Destroying FCFS scheduler...");
}

void FcfsScheduler::RunWithMemorySimulation()
{
	DLog("Running process simulation with memory simulation enabled");

	const size_t numProcesses = processQueue.size();
	std::ostringstream memDumpStringStream;

	if (numProcesses != 0)
	{
		Output() << "Process Scheduling Times (start/end):" << std::endl;

		// Set the clock to the start time of the first job
		simulationClock = processQueue[0].ArrivalTime();

		for (size_t i = 0; i < numProcesses; ++i)
		{
			Process * p = &processQueue[i];
			p->StartTime() = simulationClock;
			memoryManager.LoadProcess(p);

			for (;;)
			{
				std::string codeLine;
				int oldClock = simulationClock;
				MemoryManager::MemoryAccessResult result = memoryManager.NextCodeLine(simulationClock, codeLine);
				stepsElapsedSinceLastMemDump += simulationClock - oldClock;

				if (stepsElapsedSinceLastMemDump >= memDumpTimeStep)
				{
					memoryManager.PrintMemoryDump(memDumpStringStream, simulationClock);
					stepsElapsedSinceLastMemDump = 0;
				}

				if (result == MemoryManager::NoMoreCode)
				{
					break;
				}

				p->ExecuteCodeLine(codeLine);
			}

			p->EndTime() = simulationClock++;

			Output() << p->Name().c_str() << " " << std::setfill(' ') << std::setw(2) << p->StartTime() << " "
				<< std::setfill(' ') << std::setw(2) << p->EndTime() << std::endl;

			memoryManager.UnloadProcess(p);
		}
	}

	Output() << std::endl;
	Output() << "Memory Simulation Dump:" << std::endl;
	Output() << memDumpStringStream.str().c_str();

	DLog("Simulation finished");
	DLog("Simulated " << numProcesses << " processes");
}

void FcfsScheduler::RunWithoutMemorySimulation()
{
	DLog("Running process simulation without memory simulation");

	const size_t numProcesses = processQueue.size();

	if (numProcesses != 0)
	{
		Output() << "Process Scheduling Times (start/end):" << std::endl;

		// Set the clock to the start time of the first job
		simulationClock = processQueue[0].ArrivalTime();

		for (size_t i = 0; i < numProcesses; ++i)
		{
			Process * p = &processQueue[i];
			p->StartTime() = simulationClock;

			for (;;)
			{
				std::string codeLine;
				const int nextCodeLine = p->NextCodeLine();

				if (nextCodeLine < (int)p->CodeLines().size())
				{
					codeLine = p->CodeLines()[nextCodeLine];
					p->ExecuteCodeLine(codeLine);
					simulationClock++;
				}
				else
				{
					break;
				}
			}

			p->EndTime() = simulationClock++;

			Output() << p->Name().c_str() << " " << std::setfill(' ') << std::setw(2) << p->StartTime() << " "
				<< std::setfill(' ') << std::setw(2) << p->EndTime() << std::endl;
		}
	}

	DLog("Simulation finished");
	DLog("Simulated " << numProcesses << " processes");
}
